package cn.taobaoke.restful.service;

import cn.taobaoke.restful.domain.*;
import cn.taobaoke.restful.exception.TBKException;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * AccountsService类.
 * +-----------------------------------------------------------------------------------------------+
 * |类名称: AccountsService                                                                         |
 * |创建时间: 5/31/17                                                                               |
 * |功能简介:                                                                                       |
 * |参考链接:                                                                                       |
 * +-----------------------------------------------------------------------------------------------+
 *
 * @author luch
 */
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class AccountsService {


    public List<AccountsEntity> getAgentAccounts(final Long agentId, final Long domainId, String domain) {
        logger.info("getAgentAccounts by id => {}", agentId);
        return accountsV2Repository.getAccounts(domainId, domain);//
//        return accountsRepository.findByAgentIdOrderByDateDesc(agentId, domainId);
    }

    public List<AccountsEntity> getAdminAgentAccounts(String keyword, final Long domainId, String domain) {
        keyword = "%" + keyword + "%";

        List<AgentEntity> agents = agentRepository.findByKeywords(keyword, domainId);
//        Page<AgentEntity> agents = agentRepository.findByKeywordPage(keyword, pageable);
        if (agents.size() <= 0) return Collections.EMPTY_LIST;

        List<Long> agentIds = new ArrayList<>();
        for (AgentEntity agent : agents) {
            agentIds.add(agent.getId());
        }

//        List<AccountsEntity> accounts = accountsRepository.findByDomainIdAndAgentIdIn(domainId, agentIds);
        List<AccountsEntity> accounts = accountsV2Repository.findByDomainAndAgentIdIn(domainId, domain, agentIds);
        wrapAgentForAccounts(accounts, domainId);
        return accounts;
//        return new PageImpl<>(accounts, pageable, agents.getTotalElements());
    }

    public void payAccounts(Long accountsId, Double realAccount, final Long domainId, String domain) {

        val accountOpt = accountsV2Repository.findByIdAndDomain(accountsId, domainId, domain);
//        val accountOpt = accountsRepository.findByIdAndDomainId(accountsId, domainId);
        if (! accountOpt.isPresent()) throw new TBKException("不存在的 accountsId => " + accountsId);

        AccountsEntity accountsEntity = accountOpt.get();
        accountsEntity.setRealAccount(realAccount);
        accountsEntity.setIsPayed(true);
        accountsEntity.setUpdateAt(new Date());
//        accountsRepository.save(accountsEntity);
        accountsV2Repository.save(accountsEntity, domain);

        // 账户余额通过计算获取,不存储。
        // 自动将前面的结算掉
        String date = accountsEntity.getDate();
//        accountsRepository.setPayedByDateLessThan(date, domainId);
        accountsV2Repository.setPayedByDateLessThan(date, domain);
    }

    public Workbook exportAccountStats(final Long domainId, String domain) {

        List<AccountsEntity> accountsEntities = accountsV2Repository.getAccounts(domainId, domain);

        List<String> dateList = accountsEntities.stream().map(AccountsEntity::getDate).distinct().sorted().collect(Collectors.toList());
        Map<Long, List<AccountsEntity>> groupByAgent = accountsEntities.stream().filter(e -> e.getAgentId() != null).collect(Collectors.groupingBy(AccountsEntity::getAgentId));

        Map<String, AccountsEntity> result = new HashMap<>();
        groupByAgent.forEach((agentId, list) -> {
            Optional<AgentEntity> entityOptional = agentRepository.findByIdAndDomainId(agentId, domainId);
            if (entityOptional.isPresent()) {
                AccountsEntity accEntity = list.stream().reduce(new AccountsEntity(), (acc, next) -> {

                    // 格式：null:2017-02|10￥/30￥:2017-03|10￥/30￥
                    acc.setDate(acc.getDate() + DEFAULT_SPLIT + next.getDate() + CONTENT_SPLIT + handleNumber(next.getRealAccount()) + "￥/" + handleNumber(next.getIncome()) + "￥");
                    acc.setIncome(handleNumber(acc.getIncome()) + handleNumber(next.getIncome()));
                    acc.setRealAccount(handleNumber(acc.getRealAccount()) + handleNumber(next.getRealAccount()));
                    return acc;
                });

                result.put(entityOptional.get().getName() + DEFAULT_SPLIT + entityOptional.get().getAlipay(), accEntity);
            } else {
                // pass
            }
        });

        Workbook workbook = new HSSFWorkbook();

        CellStyle titleStyle = workbook.createCellStyle();
        Font font = workbook.createFont();
        font.setBold(true);
        titleStyle.setAlignment(HorizontalAlignment.CENTER);
        titleStyle.setFont(font);

        Sheet sheet = workbook.createSheet("sheet0");
        Row titleRow = sheet.createRow(0);
        titleRow.createCell(0).setCellValue("代理名");
        titleRow.createCell(1).setCellValue("支付宝账号");
        titleRow.createCell(2).setCellValue("待结算金额");
        titleRow.createCell(3).setCellValue("总收入");
        titleRow.createCell(4).setCellValue("实际结算金额");

        titleRow.getCell(0).setCellStyle(titleStyle);
        titleRow.getCell(1).setCellStyle(titleStyle);
        titleRow.getCell(2).setCellStyle(titleStyle);
        titleRow.getCell(3).setCellStyle(titleStyle);
        titleRow.getCell(4).setCellStyle(titleStyle);

        Map<String, Integer> mapping = new HashMap<>();
        for (int i = 0; i < dateList.size(); i++) {
            titleRow.createCell(5 + i).setCellValue(dateList.get(i));
            titleRow.getCell(5 + i).setCellStyle(titleStyle);
            mapping.put(dateList.get(i), 5 + i);
        }

        CellStyle rowStyple = workbook.createCellStyle();
        rowStyple.setAlignment(HorizontalAlignment.CENTER);

        int rowNum = 1;
        for (Map.Entry<String, AccountsEntity> entry : result.entrySet()) {
            Row row = sheet.createRow(rowNum);
            AccountsEntity accountsEntity = entry.getValue();

            String[] tokens = entry.getKey().split(DEFAULT_SPLIT);
            row.createCell(0).setCellValue(tokens[0]);
            if (tokens.length > 1)
                row.createCell(1).setCellValue(handleNullStr(tokens[1]));
            else
                row.createCell(1).setCellValue("");

            Double remain = accountsEntity.getIncome() - accountsEntity.getRealAccount();
//            row.createCell(2).setCellValue(remain < 0.001 ? "--" : remain + "￥");
            row.createCell(2).setCellValue(remain + "￥");

            row.createCell(3).setCellValue(accountsEntity.getIncome() + "￥");
            row.createCell(4).setCellValue(accountsEntity.getRealAccount() + "￥");

            row.getCell(0).setCellStyle(rowStyple);
            row.getCell(1).setCellStyle(rowStyple);
            row.getCell(2).setCellStyle(rowStyple);
            row.getCell(3).setCellStyle(rowStyple);
            row.getCell(4).setCellStyle(rowStyple);

            for (int i = 0; i < dateList.size(); i++) {
                row.createCell(5 + i);
                row.getCell(5 + i).setCellStyle(rowStyple);
            }

            tokens = accountsEntity.getDate().split(DEFAULT_SPLIT);
            for (int j = 1; j < tokens.length; j++) { // 忽略第一个占位数据
                String[] items = tokens[j].split(CONTENT_SPLIT);
                row.getCell(mapping.get(items[0])).setCellValue(items[1]);
            }

            rowNum++;
        }

        return workbook;
    }

    private void wrapAgentForAccounts(final List<AccountsEntity> accounts, final Long domainId) {
        if (accounts == null || accounts.isEmpty()) return;

        List<Long> agentIds = new ArrayList<>(accounts.size());
        for (AccountsEntity account : accounts) {
            if (account.getAgentId() != null) {
                agentIds.add(account.getAgentId());
            }
        }

        List<AgentEntity> agents = agentRepository.findByIdIn(agentIds, domainId);
        for (AccountsEntity account : accounts) {
            Long agentId = account.getAgentId();
            if (agentId != null) {
                for (AgentEntity agent : agents) {
                    if (agent.getId().longValue() == agentId.longValue()) {
                        account.setAgent(filter(agent));
                        break;
                    }
                }
            }
            account.setAgentId(null);
        }
    }

    private AgentEntity filter(AgentEntity agent) {
        AgentEntity newAgent = new AgentEntity();
        newAgent.setId(agent.getId());
        newAgent.setParentId(agent.getParentId());
        newAgent.setGrandParentId(agent.getGrandParentId());
        newAgent.setName(agent.getName());
        newAgent.setWeChat(agent.getWeChat());
        newAgent.setAlipay(agent.getAlipay());
        newAgent.setLevel(agent.getLevel());
        newAgent.setPid(agent.getPid());
        newAgent.setPhone(agent.getPhone());
        return newAgent;
    }

    private String handleNullStr(String str) {
        return "null".equals(str) ? "" : str;
    }

    private Double handleNumber(Double d) {
        return d == null ? 0 : d;
    }

    private static final String CONTENT_SPLIT = "=";
    private static final String DEFAULT_SPLIT = ":";

//    private final @NonNull AccountsRepository accountsRepository;

    private final @NonNull AccountsV2Repository accountsV2Repository;

    private final @NonNull AgentRepository agentRepository;

    private static Logger logger = LogManager.getLogger(AccountsService.class);

}
